package demo

import (
	"context"
	"fmt"
	"time"

	etcdclient "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/client/v3/concurrency"
)

func init() {
	Register("EtcdConcurrency", func() Service {
		return new(EtcdConcurrency)
	})

	fmt.Println("EtcdConcurrency registered")
}

type EtcdConcurrency struct{}

func (ec *EtcdConcurrency) Exec() {
	cli, err := etcdclient.New(etcdclient.Config{
		Endpoints:   []string{"http://localhost:2379"},
		DialTimeout: 5 * time.Second,
	})

	if err != nil {
		fmt.Printf("failed to etcd_concurrency: %v\n", err)
	}
	defer cli.Close()

	// 创建两个单独的会话用来演示锁竞争
	s1, err := concurrency.NewSession(cli)
	if err != nil {
		fmt.Printf("failed to etcd_concurrency session1: %v\n", err)
		return
	}
	defer s1.Close()
	m1 := concurrency.NewMutex(s1, "/my-lock/")

	s2, err := concurrency.NewSession(cli)
	if err != nil {
		fmt.Printf("failed to etcd_concurrency session2: %v\n", err)
		return
	}
	defer s2.Close()
	m2 := concurrency.NewMutex(s2, "/my-lock/")

	// 会话s1获取锁
	if err := m1.Lock(context.TODO()); err != nil {
		fmt.Printf("failed to etcd_concurrency lock1: %v\n", err)
		return
	}
	fmt.Println("acquired lock for s1")

	m2Locked := make(chan struct{})
	go func() {
		defer close(m2Locked)
		// 等待直到会话s1释放了/my-lock/的锁
		if err := m2.Lock(context.TODO()); err != nil {
			fmt.Printf("failed to etcd_concurrency lock2: %v\n", err)
		}
	}()

	if err := m1.Unlock(context.TODO()); err != nil {
		fmt.Printf("failed to etcd_concurrency unlock: %v\n", err)
	}
	fmt.Println("released lock for s1")

	<-m2Locked
	fmt.Println("acquired lock for s2")
}
